#ifndef _v4f_hpp
#define _v4f_hpp

#include "Math.h"
#include "CrTypes.h"
#include <xmmintrin.h>
#include <algorithm>
#include <math.h>

///	Fast float 4-tuple

/**

@ingroup Core
@ingroup Math

This is the best method of performing fast vector mathematics due to its use of dylans assembler patch
to produce code that can be re-ordered as the compiler sees fit, taking advantage of register caching between
calculations.

Addition, Subtraction, Multiplication all implement overloading of +,-,*,+=,-= & *= (for 4 component maths)
For 3 component maths, just use the operators anyway except for operations where
the result is vector-length dependent (e.g. dot, cross, length), in which case
there are no defaults. 2, 3 or 4 must be specified.

@note Do not add a Vec4f(const Vec4f &) constructor! Cripples performance!

**/

namespace cr
{
	class Vec4f
	{
	public:

		uint128_t packed;

		Vec4f ();											///< default constructor (LEAVES UNINITIALISED!)
		Vec4f (float _x, float _y, float _z);				///< x,y,z constructor
		Vec4f (float _x, float _y, float _z, float _w);	///< x,y,z,w constructor

		static Vec4f x(float _x);				///< y,z,w are !undefined!

		//	Conversions to allow us to use this and uint128_t interchangeably

		Vec4f (uint128_t variable);
		operator uint128_t() const;

		//	Get individual components. Avoid, obviously.

		float getX() const;
		float getY() const;
		float getZ() const;
		float getW() const;

		void setX(float);
		void setY(float);
		void setZ(float);
		void setW(float);

		float operator[](int) const;
		float &operator[](int);				///< May cause problems for optimiser (thunk register to memory).

		//	Often need to dictate what W is...

		Vec4f getXYZ_W0() const;		///< Returns {x,y,z,0}
		Vec4f getXYZ_W1() const;		///< Returns {x,y,z,1}

		// Conversion to other class fuctions here

		// operators...apply to all 4 elements	
		Vec4f operator+(const Vec4f& right) const;
		void operator+=(const Vec4f& right);

		//Vec4f operator+(float offset) const;
		//void operator+=(float offset);

		Vec4f operator-(const Vec4f& right) const;
		void operator-=(const Vec4f& right);

		Vec4f operator*(const Vec4f& right) const;
		void operator*=(const Vec4f& right);

		Vec4f operator*(float scale) const;
		void operator*=(float scale);

		Vec4f operator/(float scale) const;
		void operator/=(float scale);

		// functions with vector length unspecified..."func" calls "func4" (inlined)
		Vec4f abs() const;
		Vec4f inv() const;

		// PER-ELEMENT OPERATIONS   essentially: .p component independent of .q,  (p != q)

		// probably dont want all the 3-vector versions

		// absolute
		Vec4f abs3() const;			///< returns |Vec4f.p|		where p is x,y,z
		Vec4f abs4() const;			///< returns |Vec4f.p|		where p is x,y,z & w

		// inverse
		Vec4f inv3() const;					///< return 1.0f/Vec4f.p		where p = x,y.z
		Vec4f inv4() const;					///< return 1.0f/Vec4f.p		where p = x,y.z.w

		// max/min (hmmm do we want some funcs to return max ?)

		Vec4f max3(const Vec4f& val) const;			///< return max(Vec4f.p,val.p)	where p is x,y & z
		Vec4f min3(const Vec4f& val) const;			///< return min(Vec4f.p,val.p)	where p is x,y & z

		Vec4f max4(const Vec4f& val) const;			///< return max(Vec4f.p,val.p)	where p is x,y,z & w
		Vec4f min4(const Vec4f& val) const;			///< return min(Vec4f.p,val.p)	where p is x,y,z & w

		Vec4f sign4() const;					///< return (-1, 0, -1) per x,y,z,w if (+ve, 0, -ve)

		/*
		void maxwith3(Vec4f val) const;			///< return max(Vec4f.p,val.p)	where p is x,y & z
		void minwith3(Vec4f val) const;			///< return min(Vec4f.p,val.p)	where p is x,y & z

		void maxwith4(Vec4f val) const;			///< return max(Vec4f.p,val.p)	where p is x,y,z & w
		void minwith4(Vec4f val) const;			///< return min(Vec4f.p,val.p)	where p is x,y,z & w
		*/

		Vec4f mulx3(const Vec4f& v) const;				///< returns this.xyz * v.x
		Vec4f mulx4(const Vec4f& v) const;				///< returns this.xyzw * v.x

		Vec4f muly3(const Vec4f& v) const;				///< returns this.xyz * v.y
		Vec4f muly4(const Vec4f& v) const;				///< returns this.xyzw * v.y

		Vec4f mulz3(const Vec4f&  v) const;				///< returns this.xyz * v.z
		Vec4f mulz4(const Vec4f&  v) const;				///< returns this.xyzw * v.z

		Vec4f mulw3(const Vec4f&  v) const;				///< returns this.xyz * v.w
		Vec4f mulw4(const Vec4f&  v) const;				///< returns this.xyzw * v.w

		///< offset
		Vec4f offset3(float offset) const;	///< returns Vec4f.p + offset	where p is x,y,z
		Vec4f offset4(float offset) const;	///< returns Vec4f.p + offset	where p is x,y,z & w

		///< scale
		Vec4f scale3(float scale) const;		///< returns Vec4f.p * scale	where p is x,y,z
		Vec4f scale4(float scale) const;		///< returns Vec4f.p * scale	where p is x,y,z & w

		///< add
		Vec4f add3(const Vec4f& right) const;		///< returns Vec4f.p + right.p	where p is x,y,z
		Vec4f add4(const Vec4f& right) const;		///< returns Vec4f.p + right.p	where p is x,y,z & w

		///< sub
		Vec4f sub3(const Vec4f& right) const;		///< returns Vec4f.p - right.p	where p is x,y,z
		Vec4f sub4(const Vec4f& right) const;		///< returns Vec4f.p - right.p	where p is x,y,z & w

		///< mul
		Vec4f mul3(const Vec4f& right) const;		///< returns Vec4f.p * right.p	where p is x,y,z
		Vec4f mul4(const Vec4f& right) const;		///< returns Vec4f.p * right.p	where p is x,y,z & w

		///< sqrt
		Vec4f sqrt3(const Vec4f& right) const;
		Vec4f sqrt4(const Vec4f& right) const;

		///< conversion
		void toFix0DP3();				///</< converts each component of Vec4f to a fixed point number of 0 dps
		void toFix0DP3(const Vec4f& val);

		void toFix4DP3();				///< converts each component of Vec4f to a fixed point number of 4 dps
		void toFix4DP3(const Vec4f& val);

		void toFix12DP3();				///< converts each component of Vec4f to a fixed point number of 12 dps
		void toFix12DP3(const Vec4f& val);

		void toFix15DP3();				///< converts each component of Vec4f to a fixed point number of 15 dps
		void toFix15DP3(const Vec4f& val);

		void toFloat0DP3();				///< converts each component (0 dps) of Vec4f to a floating point number
		void toFloat0DP3(const Vec4f& val);

		void toFloat4DP3();				///< converts each component (4 dps) of Vec4f to a floating point number
		void toFloat4DP3(const Vec4f& val);

		void toFloat12DP3();			///< converts each component (12 dps) of Vec4f to a floating point number
		void toFloat12DP3(const Vec4f& val);

		void toFloat15DP3();			///< converts each component (15 dps) of Vec4f to a floating point number
		void toFloat15DP3(const Vec4f& val);

		void toFix0DP4();				///< converts each component of Vec4f to a fixed point number of 0 dps
		void toFix0DP4(const Vec4f& val);		///< (and assigns to this)

		void toFix4DP4();				///< converts each component of Vec4f to a fixed point number of 4 dps
		void toFix4DP4(const Vec4f& val);		///< (and assigns to this)

		void toFix12DP4();				///< converts each component of Vec4f to a fixed point number of 12 dps
		void toFix12DP4(const Vec4f& val);		///< (and assigns to this)

		void toFix15DP4();				///< converts each component of Vec4f to a fixed point number of 15 dps
		void toFix15DP4(const Vec4f& val);		///< (and assigns to this)

		void toFloat0DP4();				///< converts each component (0 dps) of Vec4f to a floating point number
		void toFloat0DP4(const Vec4f& val);		///< (and assigns to this)

		void toFloat4DP4();				///< converts each component (4 dps) of Vec4f to a floating point number
		void toFloat4DP4(const Vec4f& val);		///< (and assigns to this)

		void toFloat12DP4();			///< converts each component (12 dps) of Vec4f to a floating point number
		void toFloat12DP4(const Vec4f& val);		///< (and assigns to this)

		void toFloat15DP4();			///< converts each component (15 dps) of Vec4f to a floating point number
		void toFloat15DP4(const Vec4f& val);		///< (and assigns to this)


		// VECTOR-LENGTH-DEPENDENT OPERATIONS

		float dot2(const Vec4f& val) const;		///< 2-component dot
		float dot3(const Vec4f& val) const;		///< returns dot product of Vec4f with val
		float dot4(const Vec4f& val) const;		///< returns 4 component dot product of Vec4f with val

		Vec4f cross3(const Vec4f& val) const;			///< returns cross product of Vec4f with val, w unaffected
		void cross3(const Vec4f& val1, const Vec4f& val2);	///< Vec4f = cross product of val1 with val2, w unaffected

		Vec4f cross3_W0(const Vec4f& val) const;			///< returns cross product of Vec4f with val, w = 0
		void cross3_W0(const Vec4f& val1, const Vec4f& val2);		///< Vec4f = cross product of val1 with val2, w = 0

		float sumElements2() const;		///< returns Vec4f.x + Vec4f.y
		float sumElements3() const;		///< returns Vec4f.x + Vec4f.y + Vec4f.z
		float sumElements4() const;		///< returns Vec4f.x + Vec4f.y + Vec4f.z + Vec4f.w

		float length2() const;					///< returns length of 2d vector
		float lengthSquared2() const;			///< returns dot product of self
		float distance2( const Vec4f& v ) const;			///< returns 2d distance with the passed vector
		float distanceSquared2( const Vec4f& v ) const;	///< returns squared 2d distance with the passed vector

		float length3() const;					///< returns length of 3d vector
		float lengthSquared3() const;			///< returns dot product of self
		float distance3( const Vec4f& v ) const;			///< returns 3d distance with the passed vector
		float distanceSquared3( const Vec4f& v ) const;	///< returns squared 3d distance with the passed vector

		float length4() const;					///< returns length of 4d vector	
		float lengthSquared4() const;			///< returns dot product of self
		float distance4( const Vec4f& v ) const;			///< returns 4d distance with the passed vector
		float distanceSquared4( const Vec4f& v ) const;	///< returns squared 4d distance with the passed vector

		void normalise2();						///< Normalises the 2d vector
		void normalise3();						///< Normalises the 3d vector
		void normalise4();						///< Normalises the 4d vector

		Vec4f normalised2() const;				///< returns a normalised version of vector
		Vec4f normalised3() const;			
		Vec4f normalised4() const;			

		int cliptest(float bound);				///< returns  int of 6 bitflags (x > bound, x < -bound, y > bound, y < -bound, z > bound, z < -bound)

		//	Some functions to help compare directions

		int   majorAxis3() const;				///< Returns 0 iff x>y & x>z, 1 iff y>x & y>z, 2 else
		int   minorAxis3() const;				///< Returns 0 iff x<y & x<z, 1 iff y<x & y<z, 2 else

		Vec4f   tangentXY() const;				///< Returns {-Y,X,Z,W}
		Vec4f   tangentXZ() const;				///< Returns {Z,Y,-X,W}
		Vec4f   tangentYZ() const;				///< Returns {X,-Z,Y,W}

		float	headingXZ() const;				///< Returns atan2f(X,Z)

		//	X,Z functions - no affect to Y or W (useful for 2D algebra, often in AI, etc.)

		float dotXZ(const Vec4f& val) const;				///< Returns this.X*that.X + this.Z*that.Z
		float lengthXZ() const;					///< Returns sqrt(this.dotXZ(this))
		float lengthSquaredXZ() const;			///< Returns this.dotXZ(this)
		void  normaliseXZ();
		Vec4f  normalisedXZ() const;
		float sumElementsXZ() const;		///< returns Vec4f.x + Vec4f.z


		float distanceXZ( const Vec4f& v ) const;		///< returns XZ distance with the passed vector
		float distanceSquaredXZ( const Vec4f& v ) const;	///< returns squared XZ distance with the passed vector

		bool operator ==(const Vec4f&) const;	///< W IS IGNORED!

		//	Handy constants

		static const Vec4f    Xaxis,		///< 1,0,0,1
			Yaxis,		///< 0,1,0,1
			Zaxis,		///< 0,0,1,1
			Waxis,		///< 0,0,0,1

			XZaxis,		///< 1,0,1,1
			YZaxis,		///< 0,1,1,1
			XYaxis,		///< 1,1,0,1

			NegXaxis,	///< -1,1,1,1
			NegYaxis,	///< 1,-1,1,1
			NegZaxis,	///< 1,1,-1,1

			One,		///< 1,1,1,1
			Zero3,		///< 0,0,0,1
			Zero4,		///< 0,0,0,0
			Zero,		///< 0,0,0,1

			FLT_MAX4,	///< FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX
			FLT_MIN4;	///< FLT_MIN, FLT_MIN, FLT_MIN, FLT_MIN
	};

	Vec4f operator -(const Vec4f& v);		///< For evaluating a = -b (={-x,-y,-z,-w}
	Vec4f operator +(const Vec4f& v);		///< For evaluating a = +b (does nothing)

	///
	///		Inlines
	///

	//lint -e{1401} suppress "packed not initialized"

	inline Vec4f::Vec4f()
	{
	}

	inline Vec4f::Vec4f(const uint128_t variable)
	{
		packed=variable;
	}

	inline Vec4f::operator uint128_t() const
	{
		return packed;
	}


	///
	///		Platform dependent inlines
	///


	inline Vec4f::Vec4f(float _x, float _y, float _z, float _w)
	{
		packed.f32[0]=_x;
		packed.f32[1]=_y;
		packed.f32[2]=_z;
		packed.f32[3]=_w;
	}

	inline Vec4f::Vec4f(float _x, float _y, float _z)
	{
		((float *)&packed)[0]=_x;
		((float *)&packed)[1]=_y;
		((float *)&packed)[2]=_z;
	}

	inline Vec4f Vec4f::x(float _x)
	{
		Vec4f v;
		v.packed.f32[0]=_x;
		return v;
	}

	inline float Vec4f::getX() const
	{
		return packed.f32[0];
	}

	inline float Vec4f::getY() const
	{
		return packed.f32[1];
	}

	inline float Vec4f::getZ() const
	{
		return packed.f32[2];
	}

	inline float Vec4f::getW() const
	{
		return packed.f32[3];
	}

	inline void Vec4f::setX(float x)
	{
		packed.f32[0]=x;
	}

	inline void Vec4f::setY(float y)
	{
		packed.f32[1]=y;
	}

	inline void Vec4f::setZ(float z)
	{
		packed.f32[2]=z;
	}

	inline void Vec4f::setW(float w)
	{
		packed.f32[3]=w;
	}

	inline Vec4f Vec4f::scale4(float scale) const
	{
		return Vec4f(	getX() * scale, getY() * scale, getZ() * scale, getW() * scale);
	}

	inline Vec4f Vec4f::scale3(float scale) const
	{
		return Vec4f(	scale*getX(), scale*getY(), scale*getZ(), getW());
	}

	inline Vec4f Vec4f::mulx4(const Vec4f& v) const
	{
		return scale4(v.getX());
	}

	inline Vec4f Vec4f::mulx3(const Vec4f& v) const
	{
		return scale3(v.getX());
	}

	inline Vec4f Vec4f::muly4(const Vec4f& v) const
	{
		return scale4(v.getY());
	}

	inline Vec4f Vec4f::muly3(const Vec4f& v) const
	{
		return scale3(v.getY());
	}

	inline Vec4f Vec4f::mulz4(const Vec4f& v) const
	{
		return scale4(v.getZ());
	}

	inline Vec4f Vec4f::mulz3(const Vec4f& v) const
	{
		return scale3(v.getZ());
	}

	inline Vec4f Vec4f::mulw4(const Vec4f& v) const
	{
		return scale4(v.getW());
	}

	inline Vec4f Vec4f::mulw3(const Vec4f& v) const
	{
		return scale3(v.getW());
	}

	inline Vec4f Vec4f::add4(const Vec4f& v) const
	{
		return Vec4f(	getX() + v.getX(), getY() + v.getY(), getZ() + v.getZ(), getW() + v.getW());
	}

	inline Vec4f Vec4f::add3(const Vec4f& v) const
	{
		return Vec4f(	getX() + v.getX(), getY() + v.getY(), getZ() + v.getZ(), getW() );
	}

	inline Vec4f Vec4f::mul4(const Vec4f& v) const
	{
		return Vec4f(	getX() * v.getX(), getY() * v.getY(), getZ() * v.getZ(), getW() * v.getW() );
	}

	inline Vec4f Vec4f::sub4(const Vec4f& v) const
	{
		return Vec4f(	getX() - v.getX(), getY() - v.getY(), getZ() - v.getZ(), getW() - v.getW() );
	}

	inline Vec4f Vec4f::sub3(const Vec4f& v) const
	{
		return Vec4f(	getX() - v.getX(), getY() - v.getY(), getZ() - v.getZ(), getW() );
	}

	inline Vec4f operator-(const Vec4f& v)
	{
		return Vec4f(	-v.getX(), -v.getY(), -v.getZ(), -v.getW() );
	}

	inline float Vec4f::dot3(const Vec4f& v) const
	{
		float x1=getX();
		float y1=getY();
		float z1=getZ();
		float x2=v.getX();
		float y2=v.getY();
		float z2=v.getZ();
		return x1*x2 + y1*y2 + z1*z2;
	}

	inline float Vec4f::length3() const
	{
		float x=getX();
		float y=getY();
		float z=getZ();
		return sqrtf(x*x + y*y + z*z);
	}

	inline float Vec4f::dot4(const Vec4f& v) const
	{
		float x1=getX();
		float y1=getY();
		float z1=getZ();
		float w1=getW();
		float x2=v.getX();
		float y2=v.getY();
		float z2=v.getZ();
		float w2=v.getW();
		return x1*x2 + y1*y2 + z1*z2 + w1*w2;
	}

	inline float Vec4f::length4() const
	{
		float x=getX();
		float y=getY();
		float z=getZ();
		float w=getW();
		return sqrtf(x*x + y*y + z*z + w*w);
	}

	inline bool Vec4f::operator==(const Vec4f& v) const
	{
		return	packed.f32[0] == v.packed.f32[0] &&
			packed.f32[1] == v.packed.f32[1] &&
			packed.f32[2] == v.packed.f32[2];

	}

	inline Vec4f Vec4f::max3(const Vec4f& val) const
	{
		CR_UNUSED( val );

		Vec4f max;

		//max.setX(std::max(val.getX(), getX()));
		//max.setY(std::max(val.getY(), getY()));
		//max.setZ(std::max(val.getZ(), getZ()));
		//max.setW(1.0f);

		return max;

	}

	inline Vec4f Vec4f::min3(const Vec4f& val) const
	{
		CR_UNUSED( val );

		Vec4f min;

		//min.setX(::min(val.getX(), getX()));
		//min.setY(::min(val.getY(), getY()));
		//min.setZ(::min(val.getZ(), getZ()));
		//min.setW(1.0f);
		return min;

	}

	inline Vec4f Vec4f::max4(const Vec4f& val) const
	{
		CR_UNUSED( val );

		Vec4f max;


		///max.setX(::max(val.getX(), getX()));
		//max.setY(::max(val.getY(), getY()));
		//max.setZ(::max(val.getZ(), getZ()));
		//max.setW(::max(val.getW(), getW()));
		return max;

	}

	inline Vec4f Vec4f::min4(const Vec4f& val) const
	{
		CR_UNUSED( val );

		Vec4f min;

		//min.setX(::min(val.getX(), getX()));
		//min.setY(::min(val.getY(), getY()));
		//min.setZ(::min(val.getZ(), getZ()));
		//min.setW(::min(val.getW(), getW()));
		return min;
	}

	// absolut
	inline Vec4f Vec4f::abs3() const
	{
		Vec4f returnval;

		returnval.setX(fabsf(getX()));
		returnval.setY(fabsf(getY()));
		returnval.setZ(fabsf(getZ()));
		returnval.setW(getW());

		return returnval;
	}

	inline Vec4f Vec4f::abs4() const
	{
		Vec4f returnval;

		returnval.setX(fabsf(getX()));
		returnval.setY(fabsf(getY()));
		returnval.setZ(fabsf(getZ()));
		returnval.setW(fabsf(getW()));
		return returnval;
	}



	///
	///		Inlines upon inlines
	///

	inline Vec4f Vec4f::operator-(const Vec4f& right) const 
	{ 
		return sub4(right); 
	}

	inline float Vec4f::lengthSquared2() const
	{
		return dot2(*this);
	}

	inline float Vec4f::lengthSquared3() const
	{
		return dot3(*this);
	}

	inline float Vec4f::lengthSquared4() const
	{
		return dot4(*this);
	}

	inline float Vec4f::lengthSquaredXZ() const
	{
		return dotXZ(*this);
	}

	inline float Vec4f::distance2( const Vec4f& v ) const
	{
		return (*this-v).length2();
	}

	inline float Vec4f::distanceSquared2( const Vec4f& v ) const
	{
		return (*this-v).lengthSquared2();
	}

	inline float Vec4f::distance3( const Vec4f& v ) const
	{
		return (*this-v).length3();
	}

	inline float Vec4f::distanceSquared3( const Vec4f& v ) const
	{
		return (*this-v).lengthSquared3();
	}

	inline float Vec4f::distance4( const Vec4f& v ) const
	{
		return (*this-v).length4();
	}

	inline float Vec4f::distanceSquared4( const Vec4f& v ) const
	{
		return (*this-v).lengthSquared4();
	}

	inline float Vec4f::distanceXZ( const Vec4f& v ) const
	{
		return (*this-v).lengthXZ();
	}

	inline float Vec4f::distanceSquaredXZ( const Vec4f& v ) const
	{
		return (*this-v).lengthSquaredXZ();
	}

	// operators...apply to all 4 elements	
	inline Vec4f Vec4f::operator+(const Vec4f& right) const 
	{ 
		return add4(right); 
	}
	inline void Vec4f::operator+=(const Vec4f& right) 
	{
		(*this) = (*this) + right;
	}

	//Vec4f Vec4f::operator+(float offset) const 
	//{
	//	return offset4(right); 
	//}

	//void Vec4f::operator+=(float offset) 
	//{ 
	//	(*this) = (*this) + offset;
	//}

	inline void Vec4f::operator-=(const Vec4f& right) 
	{ 
		(*this) = (*this) - right;
	}

	inline Vec4f Vec4f::operator*(const Vec4f& right) const 
	{ 
		return mul4(right); 
	}

	inline void Vec4f::operator*=(const Vec4f& right) 
	{ 
		(*this) = (*this) * right;
	}

	inline Vec4f Vec4f::operator*(float scale) const 
	{ 
		return scale4( scale );
	}

	inline void Vec4f::operator*=(float scale) 
	{
		(*this) = (*this) * scale;
	}

	inline Vec4f Vec4f::abs() const
	{
		return abs4();
	}

	inline Vec4f Vec4f::normalised2() const
	{ 
		Vec4f n=*this;
		n.normalise2();
		return n; 
	}

	inline Vec4f Vec4f::normalised3() const
	{ 
		Vec4f n=*this;
		n.normalise3();
		return n; 
	}

	inline Vec4f Vec4f::normalised4() const
	{ 
		Vec4f n=*this;
		n.normalise4();
		return n; 
	}


	inline Vec4f Vec4f::normalisedXZ() const
	{ 
		Vec4f n=*this;
		n.normaliseXZ();
		return n;
	}


	// non-members
	inline Vec4f operator*(float left, Vec4f right) // Vec4f.x * right.x	, Vec4f.y * right.y	, Vec4f.z * right.z
	{
		return (right * left);
	}

	//inline Vec4f operator+(float left, Vec4f right) // Vec4f.x * right.x	, Vec4f.y * right.y	, Vec4f.z * right.z
	//{
	//	return (right + left);
	//}

	inline Vec4f Vec4f::operator/(float scale) const
	{
		Vec4f result = *this;
		result *= 1.0f/scale;
		return result;
	}

	inline void Vec4f::operator/=(float scale)
	{
		*this *= 1.0f/scale;
	}

	inline Vec4f Vec4f::inv4() const
	{
		return Vec4f(1.0f / getX(), 1.0f / getY(), 1.0f / getZ(), 1.0f / getW());
	}

	inline Vec4f Vec4f::inv3() const
	{
		return Vec4f(1.0f / getX(), 1.0f / getY(), 1.0f / getZ());
	}

	inline Vec4f Vec4f::inv() const
	{ 
		return inv4(); 
	}

	inline float Vec4f::operator[] (int index) const
	{
		return ((float *)&packed)[index];
	}

	inline float &Vec4f::operator[] (int index)
	{
		return ((float *)&packed)[index];
	}

	inline float Vec4f::headingXZ() const
	{
		return atan2f(getX(), getZ());
	}

	inline Vec4f operator +(const Vec4f& val)
	{
		return val;
	}

	typedef const Vec4f& Vec4fRef;

} // namespace Core

#endif
